WOLF core
WOLF: A Modular Estimation Framework for Robotics
XXXXXXXXXXXXXXXXXXXXXXXXvoid(0)" frameborder="0" name="MSearchResults" id="MSearchResults">
covariance.h
Go to the documentation of this file.
1// WOLF - Copyright (C) 2020-2026
2// Institut de Robòtica i Informàtica Industrial, CSIC-UPC.
3// Authors: Joan Solà Ortega (jsola@iri.upc.edu) and
4// Joan Vallvé Navarro (jvallve@iri.upc.edu)
5// All rights reserved.
6//
7// This file is part of WOLF: http://www.iri.upc.edu/wolf
8// WOLF is free software: you can redistribute it and/or modify
9// it under the terms of the GNU General Public License version 3
10// as published by the Free Software Foundation.
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this program. If not, see <http://www.gnu.org/licenses/>.
19#pragma once
20
21#include <Eigen/Dense>
22
23namespace wolf
24{
25template <typename T, int N, int RC>
26inline bool isSymmetric(const Eigen::Matrix<T, N, N, RC>& M, const T eps = wolf::Constants::EPS)
27{
28 if (M.cols() != M.rows()) return false;
29 return M.isApprox(M.transpose(), eps);
30}
31
32template <typename T, int N, int RC>
33inline bool isPositiveSemiDefinite(const Eigen::Matrix<T, N, N, RC>& M, const T& eps = Constants::EPS)
34{
35 Eigen::SelfAdjointEigenSolver<Eigen::Matrix<T, N, N, RC> > eigensolver(M, Eigen::EigenvaluesOnly);
36
37 if (eigensolver.info() == Eigen::Success)
38 {
39 // All eigenvalues must be >= 0:
40 return (eigensolver.eigenvalues().array() >= eps).all();
41 }
42 else
43 std::cout << "eigen decomposition failed" << std::endl;
44
45 return false;
46}
47
48template <typename T, int N, int RC>
49inline bool isCovariance(const Eigen::Matrix<T, N, N, RC>& M, const T& eps = Constants::EPS)
50{
51 return isSymmetric(M) && isPositiveSemiDefinite(M, eps);
52}
53
54#define WOLF_ASSERT_COVARIANCE_MATRIX(x) assert(isCovariance(x, Constants::EPS_SMALL) && "Not a covariance");
55
56#define WOLF_ASSERT_INFORMATION_MATRIX(x) assert(isCovariance(x, double(0.0)) && "Not an information matrix");
57
58template <typename T, int N, int RC>
59inline bool makePosDef(Eigen::Matrix<T, N, N, RC>& M, const T& eps = Constants::EPS)
60{
61 Eigen::SelfAdjointEigenSolver<Eigen::Matrix<T, N, N, RC> > eigensolver(M);
62
63 if (eigensolver.info() == Eigen::Success)
64 {
65 // All eigenvalues must be >= 0:
66 double epsilon = eps;
67 while ((eigensolver.eigenvalues().array() < eps).any())
68 {
69 // std::cout << "----- any negative eigenvalue or too close to zero\n";
70 // std::cout << "previous eigenvalues: " << eigensolver.eigenvalues().transpose() << std::endl;
71 // std::cout << "previous determinant: " << M.determinant() << std::endl;
72 M = eigensolver.eigenvectors() * eigensolver.eigenvalues().cwiseMax(epsilon).asDiagonal() *
73 eigensolver.eigenvectors().transpose();
74 eigensolver.compute(M);
75 // std::cout << "epsilon used: " << epsilon << std::endl;
76 // std::cout << "posterior eigenvalues: " << eigensolver.eigenvalues().transpose() << std::endl;
77 // std::cout << "posterior determinant: " << M.determinant() << std::endl;
78 epsilon *= 10;
79 }
81
82 return epsilon != eps;
83 }
84 else
85 WOLF_ERROR("Couldn't compute covariance eigen decomposition");
86
87 return false;
88}
89
90inline Eigen::MatrixXd computeSqrtUpper(const Eigen::MatrixXd& _info)
91{
92 // impose symmetry
93 Eigen::MatrixXd info = _info.selfadjointView<Eigen::Upper>();
94
95 // Normal Cholesky factorization
96 Eigen::LLT<Eigen::MatrixXd> llt_of_info(info);
97 Eigen::MatrixXd R = llt_of_info.matrixU();
98
99 // Good factorization
100 if (info.isApprox(R.transpose() * R, Constants::EPS)) return R;
101
102 // Not good factorization: SelfAdjointEigenSolver
103 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(info);
104 Eigen::VectorXd eval = es.eigenvalues().real().cwiseMax(Constants::EPS);
105
106 R = eval.cwiseSqrt().asDiagonal() * es.eigenvectors().real().transpose();
107
108 return R;
109}
110
111} // namespace wolf
#define WOLF_ASSERT_COVARIANCE_MATRIX(x)
Definition: covariance.h:54
#define WOLF_ERROR(...)
Definition: logging.h:445
const double EPS
Definition: wolf.h:74
Definition: capture_base.h:23
bool isCovariance(const Eigen::Matrix< T, N, N, RC > &M, const T &eps=Constants::EPS)
Definition: covariance.h:49
Eigen::MatrixXd computeSqrtUpper(const Eigen::MatrixXd &_info)
Definition: covariance.h:90
bool isSymmetric(const Eigen::Matrix< T, N, N, RC > &M, const T eps=wolf::Constants::EPS)
Definition: covariance.h:26
bool makePosDef(Eigen::Matrix< T, N, N, RC > &M, const T &eps=Constants::EPS)
Definition: covariance.h:59
bool isPositiveSemiDefinite(const Eigen::Matrix< T, N, N, RC > &M, const T &eps=Constants::EPS)
Definition: covariance.h:33